#pragma once

#include <boost/detail/workaround.hpp>

# pragma warning(push)
# pragma warning(disable:4996)
# pragma warning(disable:4510)
# pragma warning(disable:4610)

#include <cstddef>
#include <stdexcept>
#include <algorithm>
#include <string>
#include <sstream>
#include <iostream>
#include <boost/assert.hpp>
#include <boost/swap.hpp>
#include <boost/detail/iterator.hpp>
#include <boost/throw_exception.hpp>
#include <boost/config.hpp>

using namespace std;

template<typename T>
class RefArrayData {
public:
	RefArrayData() :
			ptr(0), length(0), capality(0) {
	}
	virtual ~RefArrayData() {
		if (ptr) {
			delete[] ptr;
		}
	}
public:
	bool IncCapality(std::size_t newCapality, const T& val = T()) {
		if (newCapality <= capality) {
			return true;
		}
		T* p = new T[newCapality];
		if (p) {
			ArrayCopyEx(ptr, 0, p, 0, length); //ptr==0ʱ, lengthҲһ����0
			std::fill(p + length, p + newCapality, val);
			capality = newCapality;
			if (ptr) {
				delete[] ptr;
			}
			ptr = p;
			return true;
		}
#ifdef _DEBUG
		throw exception("Alloc Memory Failed!");
#endif
		return false;
	}
public:
	T* ptr;
	std::size_t length;
	std::size_t capality;
};
template<class T, std::size_t LEN = 0>
class RefArray {
private:
	boost::shared_ptr<RefArrayData<T> > elements;
public:
	// type definitions
	typedef T value_type;
	typedef T* iterator;
	typedef const T* const_iterator;
	typedef T& reference;
	typedef const T& const_reference;
	typedef std::size_t size_type;
	typedef std::ptrdiff_t difference_type;

	RefArray() {
		elements.reset(new RefArrayData<T>());
		resize(LEN, value_type());
	}

	RefArray(std::size_t len, const value_type& val = value_type()) {
		elements.reset(new RefArrayData<T>());
		resize(len, val);
	}
	template<std::size_t LEN2>
	RefArray(const RefArray<T, LEN2>& other) {
		elements = other.elements;
	}
	virtual ~RefArray() {
	}
	bool IncCapality(std::size_t newCapality, const value_type& val = value_type()) {
		return elements->IncCapality(newCapality, val);
	}
	bool resize(std::size_t newLen, const value_type& val = value_type()) {
		if (!IncCapality(newLen, val)) {
			return false;
		}
		elements->length = newLen;
		return true;
	}
	iterator begin() {
		if (!elements->length) {
			return iterator(reinterpret_cast<T*>(this));
		}
		return elements->ptr;
	}
	const_iterator begin() const {
		if (!elements->length) {
			return const_iterator(reinterpret_cast<const T*>(this));
		}
		return elements->ptr;
	}
	iterator end() {
		if (!elements->length) {
			return begin();
		}
		return elements->ptr + elements->length;
	}
	const_iterator end() const {
		if (!elements->length) {
			return begin();
		}
		return elements->ptr + elements->length;
	}

	// reverse iterator support
#if !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) && !defined(BOOST_MSVC_STD_ITERATOR) && !defined(BOOST_NO_STD_ITERATOR_TRAITS)
	typedef std::reverse_iterator<iterator> reverse_iterator;
	typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
#elif defined(_MSC_VER) && (_MSC_VER == 1300) && defined(BOOST_DINKUMWARE_STDLIB) && (BOOST_DINKUMWARE_STDLIB == 310)
	// workaround for broken reverse_iterator in VC7
	typedef std::reverse_iterator < std::_Ptrit < value_type, difference_type, iterator,
	reference, iterator, reference > > reverse_iterator;
	typedef std::reverse_iterator < std::_Ptrit < value_type, difference_type, const_iterator,
	const_reference, iterator, reference > > const_reverse_iterator;
#elif defined(_RWSTD_NO_CLASS_PARTIAL_SPEC)
	typedef std::reverse_iterator < iterator, std::random_access_iterator_tag,
	value_type, reference, iterator, difference_type > reverse_iterator;
	typedef std::reverse_iterator < const_iterator, std::random_access_iterator_tag,
	value_type, const_reference, const_iterator, difference_type > const_reverse_iterator;
#else
	// workaround for broken reverse_iterator implementations
	typedef std::reverse_iterator<iterator, T> reverse_iterator;
	typedef std::reverse_iterator<const_iterator, T> const_reverse_iterator;
#endif

	reverse_iterator rbegin() {
		return reverse_iterator(end());
	}
	const_reverse_iterator rbegin() const {
		return const_reverse_iterator(end());
	}
	reverse_iterator rend() {
		return reverse_iterator(begin());
	}
	const_reverse_iterator rend() const {
		return const_reverse_iterator(begin());
	}

	// operator[]
	reference operator[](size_type i) {
		BOOST_ASSERT(i < elements->length && "out of range");
		return elements->ptr[i];
	}

	const_reference operator[](size_type i) const {
		BOOST_ASSERT(i < elements->length && "out of range");
		return elements->ptr[i];
	}

	// at() with range check
	reference at(size_type i) {
		rangecheck(i);
		return elements->ptr[i];
	}
	const_reference at(size_type i) const {
		rangecheck(i);
		return elements->ptr[i];
	}

	// front() and back()
	reference front() {
		rangecheck(0);
		return elements->ptr[0];
	}

	const_reference front() const {
		rangecheck(0);
		return elements->ptr[0];
	}

	reference back() {
		rangecheck(elements->length - 1); //if N==0, N-1 ==> FFFFFFFF, rangecheck failed!
		return elements->ptr[elements->length - 1];
	}

	const_reference back() const {
		rangecheck(elements->length - 1);
		return elements->ptr[elements->length - 1];
	}

	// size is constant
	size_type size() const {
		return elements->length;
	}
	size_type length() const {
		return size();
	}
	bool empty() const {
		return 0 == elements->length;
	}
	size_type max_size() const {
		return elements->length;
	}

	template<std::size_t LEN2>
	void swap(RefArray<T, LEN2>& y) {
		elements.swap(y.elements);
	}

	// direct access to data (read-only)
	const T* data() const {
		return elements->ptr;
	}
	T* data() {
		return elements->ptr;
	}

	// use RefArray as C RefArray (direct read/write access to data)
	T* c_array() {
		return elements->ptr;
	}

	RefArray<T, LEN> Copy() const {
		RefArray<T, LEN> arr;
		arr.resize(size());
		std::copy(begin(), end(), arr.begin());
		return arr;
	}
	template<typename T2, std::size_t LEN2>
	RefArray<T, LEN>& operator=(RefArray<T2, LEN2>& rhs) {
		elements = rhs.elements;
		return *this;
	}
	// assign one value to all elements
	void assign(const T& value) {
		fill(value);       // A synonym for fill
	}
	void fill(const T& value) {
		std::fill_n(begin(), size(), value);
	}

	// check range (may be private because it is )
	void rangecheck(size_type i) const {
		if (i >= size()) {
			std::out_of_range e("RefArray<>: index out of range");
			boost::throw_exception(e);
		}
	}
};

// comparisons
template<typename T, std::size_t LEN1, std::size_t LEN2>
bool operator==(const RefArray<T, LEN1>& x, const RefArray<T, LEN2>& y) {
	return (x.N == y.N) && std::equal(x.begin(), x.end(), y.begin());
}
template<class T, std::size_t LEN1, std::size_t LEN2>
bool operator<(const RefArray<T, LEN1>& x, const RefArray<T, LEN2>& y) {
	return std::lexicographical_compare(x.begin(), x.end(), y.begin(), y.end());
}
template<class T, std::size_t LEN1, std::size_t LEN2>
bool operator!=(const RefArray<T, LEN1>& x, const RefArray<T, LEN2>& y) {
	return !(x == y);
}
template<class T, std::size_t LEN1, std::size_t LEN2>
bool operator>(const RefArray<T, LEN1>& x, const RefArray<T, LEN2>& y) {
	return y < x;
}
template<class T, std::size_t LEN1, std::size_t LEN2>
bool operator<=(const RefArray<T, LEN1>& x, const RefArray<T, LEN2>& y) {
	return !(y < x);
}
template<class T, std::size_t LEN1, std::size_t LEN2>
bool operator>=(const RefArray<T, LEN1>& x, const RefArray<T, LEN2>& y) {
	return !(x < y);
}

// global swap()
template<class T, std::size_t LEN1, std::size_t LEN2>
inline void swap(RefArray<T, LEN1>& x, RefArray<T, LEN2>& y) {
	x.swap(y);
}

template<typename T, size_t LEN>
ostream& operator<<(ostream& os, const RefArray<T, LEN>& arr) {
	for (size_t i = 0; i < arr.length(); ++i) {
		if (i != 0) {
			os << ", ";
		}
		os << arr[i];
	}
	return os;
}

# pragma warning(pop)

